package com.fll.codeworld.functionInterface;

import com.baomidou.mybatisplus.toolkit.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * @author fll
 * @description
 * @date 2022/1/4 16:07
 */
public class Filter<T> {
    public static <T> List<T> filter(List<T> list, BooleanFunctionalInterface b){
        if (CollectionUtils.isEmpty(list)){
            return new ArrayList<>(0);
        }

        List<T> result = new ArrayList<>(list.size());
        for(int i=0; i<list.size(); i++){
            T t = list.get(i);
            if (b.test(t)) {
                result.add(t);
            }
        }

        return result;
    }

    /**
     *该接口定义了一个支持泛型的boolean test( T)的抽象方法，
     * 其函数描述符为 （T）-> boolean，现在我们就可以直接使用Predicate<T>接口来替代上面自定义的接口了。
     * @param list
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> List<T> predicate(List<T> list, Predicate predicate){
        if (CollectionUtils.isEmpty(list)){
            return new ArrayList<>(0);
        }

        List<T> result = new ArrayList<>(list.size());
        for(int i=0; i<list.size(); i++){
            T t = list.get(i);
            if (predicate.test(t)) {
                result.add(t);
            }
        }

        return result;
    }

    /**
     *该接口定义了一个void accept(T)的抽象方法，其函数描述符为 (T) -> void，
     * 如果你需要一个操作某一对象，但无需返回的的函数式接口，那么就可以使用Consumer<T>接口。
     * @param list
     * @param consumer
     * @param <T>
     */
    public static <T> void consumer(List<T> list, Consumer consumer){
        if (CollectionUtils.isEmpty(list)){
            return ;
        }
        List<T> result = new ArrayList<>(list.size());
        for(int i=0; i<list.size(); i++){
            T t = list.get(i);
            consumer.accept(t);
        }

    }

    /**
     *该接口定义了一个 T get() 的抽象方法，其函数描述符为 () -> T，
     * 如果不接受入参，直接为我们生产一个指定的结果，那么就可以用Supplier<T>。
     * @param count
     * @param supplier
     * @param <T>
     * @return
     */
    public static <T> List<T> listFactory(int count, Supplier<T> supplier){

        List<T> result = new ArrayList<>(count);
        for(int i=0; i<count; i++){
            T t = supplier.get();
            result.add(t);
        }

        return result;
    }

    /**
     * 该接口定义了一个 R apply(T)类型的抽象函数，它接受一个泛型变量T，并返回一个泛型变量R，
     * 如果你需要将一个对象T映射成R，那么就可以使用Function<T,R>接口。
     * @param list
     * @param function
     * @param <T>
     * @return
     */
    public static <T> List<String> function(List<T> list, Function<T,String> function){
        if (CollectionUtils.isEmpty(list)){
            return new ArrayList<>(0);
        }

        List<String> result = new ArrayList<>(list.size());
        for(int i=0; i<list.size(); i++){
            T t = list.get(i);
            String apply = function.apply(t);
            result.add(apply);
        }

        return result;
    }
}
